using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Data;
using System.Data.SqlClient;



namespace Classes
{
	public abstract class ProviderSQL<T> : DataAccess
	{
		
		protected virtual string retornaTabela(object[] atributos)
		{
			string _table = string.Empty; 
			foreach(Attribute _atributo in atributos)
			{
				Tabela tb = _atributo as Tabela;
				_table =  tb.Nome;
			}
			return _table;
		}
		
		#region  METODOS CREATE

		protected virtual string CreateSelect(System.Type T, bool orderBy, short tipoFiltro)
		{
			var _atributos = T.GetCustomAttributes(false);
			var _campos = T.GetProperties();
			string _table = retornaTabela(_atributos);
			string _cpOrdenacao = string.Empty;
			string _cpPK = string.Empty;
			StringBuilder _sb = new StringBuilder();
			_sb.Append("SELECT ");
			
			
			foreach(var _campo in _campos)
			{
				var _atributosColunas = _campo.GetCustomAttributes(false);
				foreach(Attribute _atributoColuna in _atributosColunas)
				{
					Campos cp = _atributoColuna as Campos;
						_sb.Append(_campo.Name);
						_sb.Append(",");
					
					if(cp.OrderBy)
						_cpOrdenacao = _campo.Name;
					
					if(cp.Pk)
						_cpPK = _campo.Name;
				}
				
			}
			
			_sb.Append(", FROM ");
			_sb.Append(_table);
			
			
			//Verifica qual tipo de filtro que deve ser utilizado (1. Ordena por campo string 2. ordena pelo campo Primary Key , ou nao ordena)
			switch(tipoFiltro)
			{
			case 1: 
					_sb.Append(" WHERE ");
					_sb.Append(_cpOrdenacao);
					_sb.Append("=@descricao");
					break;
			case 2: 
					_sb.Append(" WHERE ");
					_sb.Append(_cpPK);
					_sb.Append("=@ID");
					break;
			default:
					break; 
			}
			
			
			if(orderBy)
			{
				_sb.Append(" ORDER BY");
				_sb.Append(_cpOrdenacao);
			}
				_sb.Replace(",,","");
			
			return _sb.ToString(); 
		}
				
		protected virtual string CreateDelete(System.Type T)
		{
			string _delete = String.Empty;
			var _atributos = T.GetCustomAttributes(false);
			string _table = retornaTabela(_atributos);
			var _campos = T.GetProperties(); 
			
			
			//Varredura nos campos da Tabela
			foreach(var _campo in _campos)
			{
				var _atributosColunas = _campo.GetCustomAttributes(false);
				foreach(Attribute _atributoColuna in _atributosColunas)
				{
					Campos cp = _atributoColuna as Campos;
					if(cp.Pk)
					{
						_delete =  String.Format("DELETE FROM {0} WHERE {1} = @ID",_table,cp.Nome);
					}		
				}	
			}
			return _delete;
		}
		
		protected virtual string CreateInsert(T objeto)
		{
			var _atributos = objeto.GetType().GetCustomAttributes(false);
			string _table = retornaTabela(_atributos);
			var _campos = objeto.GetType().GetProperties();
			StringBuilder _sb = new StringBuilder();
			StringBuilder _valores = new StringBuilder();
			_sb.Append("INSERT INTO {0} (");
			_valores.Append(" VALUES(");
			
			
			foreach(var _campo in _campos)
			{
				var _atributosColunas = _campo.GetCustomAttributes(false);
				foreach(Attribute _atributoColuna in _atributosColunas)
				{
					//Campos cp = _atributoColuna as Campos;
						_sb.Append(_campo.Name);
						_sb.Append(",");
							
						_valores.Append(_campo.GetValue(objeto,null).ToString());
						_valores.Append("',");
							
				}
			}
			
			_sb.Append(",)");
			_valores.Append(",)");
			
			_sb.Replace(",,","");
			_valores.Replace(",,","");
		
			_sb.Append(_valores.ToString());
			return String.Format(_sb.ToString(),_table);
		}
		
		protected virtual string CreateUpdate(T objeto)
		{
			string _chavePrimaria = string.Empty;
			string _valorChavePrimaria = string.Empty;
			var _atributos = objeto.GetType().GetCustomAttributes(false);
			string _table = retornaTabela(_atributos);
			var _campos = objeto.GetType().GetProperties();
			StringBuilder _sb = new StringBuilder();
			_sb.Append("UPDATE {0} SET ");
			
			
			foreach(var _campo in _campos)
			{
				var _atributosColunas = _campo.GetCustomAttributes(false);
				foreach(Attribute _atributoColuna in _atributosColunas)
				{
					Campos cp = _atributoColuna as Campos;
					if(cp.Pk)
					{
						_chavePrimaria = _campo.Name;
						_valorChavePrimaria = _campo.GetValue(objeto,null).ToString();
					}
					else
					{
						_sb.Append(_campo.Name);
						_sb.Append("='");
						_sb.Append(_campo.GetValue(objeto,null).ToString());
						_sb.Append("',");
					}		
				}
			}
			
			_sb.Append(", WHERE");
			_sb.Append(_chavePrimaria);
			_sb.Append("=");
			_sb.Append(_valorChavePrimaria);
			_sb.Replace(",,","");
			return String.Format(_sb.ToString(),_table);
		}
			
		#endregion
		
		#region METODOS SQL
		
		
		public int Delete(int ID)
		{
			string _sql = CreateDelete(typeof(T));
			using(SqlConnection con = new SqlConnection(this.ConnectionString))
			{
				SqlCommand cmd = new SqlCommand(_sql,con);
				cmd.CommandType = CommandType.Text;
				cmd.Parameters.Add("@ID",SqlDbType.Int).Value = ID;
				con.Open();
				int _ret = ExecuteNonQuery(cmd);
				return _ret;
			}
		}
		
		public int Update(T objeto)
		{
			string _sql = CreateUpdate(objeto);
			using(SqlConnection con = new SqlConnection(this.ConnectionString))
			{
				SqlCommand cmd = new SqlCommand(_sql,con);
				cmd.CommandType = CommandType.Text;
				con.Open();
				int _ret = ExecuteNonQuery(cmd);
				return _ret;
			}
		}
		
		public int Insert(T objeto)
		{
			string _sql = CreateInsert(objeto);
			using(SqlConnection con = new SqlConnection(this.ConnectionString))
			{
				SqlCommand cmd = new SqlCommand(_sql,con);
				cmd.CommandType = CommandType.Text;
				con.Open();
				int _ret = ExecuteNonQuery(cmd);
				return _ret;
			}
		}
		
		
		public List<T> SelectAll()
		{
			string _sql = CreateSelect(typeof(T),false,3);
			using(SqlConnection con = new SqlConnection(this.ConnectionString))
			{
				SqlCommand cmd = new SqlCommand(_sql,con);
				cmd.CommandType = CommandType.Text;
				con.Open();
				return GetItensFromReader(ExecuteReader(cmd));
			}
			
			
		}
		
		
		public List<T> GetItensFromReader(IDataReader reader)
		{
			List<T> itens = new List<T>();
			while(reader.Read())
				itens.Add(GetItem (reader));
		
			return itens;
		}
		
					
		public T GetItem(IDataReader reader)
		{
			//Cria instancia do Objeto
			object objeto = 	Activator.CreateInstance(typeof(T));
			var _campos = 		typeof(T).GetProperties();
	
			foreach(var _campo in _campos)
			{
				_campo.SetValue(objeto,reader[_campo.Name],null);	
			}
			
			return (T)objeto;		
					
		}
		
		#endregion
		
		
			
	}
		
		
}
	
	
	


